#include "stdafx.h"
#include <cstring>        // for strcmp, strstr

detour<void> R_EndFrame_Detour;
detour<int> XamInputGetState_Detour;
detour<void> CL_SendCommand_Detour;
detour<void> CL_CreateNewCommands_Detour;
detour<bool> Content_DoWeHaveContentPackDetour;


void R_EndFrameHook() {
	bool bInGame = CheckInGame();
	if (bInGame) {
		DWORD cgs_t = *(DWORD*)0x82BBAE44;
		if (cgs_t) {
			CG::bInGameCached = bInGame && *(DWORD*)(cgs_t + 0x1660) != 0;
		}
		else {
			CG::bInGameCached = false;
		}
	}
	else {
		CG::bInGameCached = bInGame;
	}

	if (CG::bInGameCached && !CG::bLobbyInitialized) {
		for (int i = 0; i < ARRAYSIZE(sCachedTags); i++) {
			sCachedTags[i] = SL_GetString(Array_TargetBone[i], 0);
		}
		sCachedRiotShield = CG_GetWeaponIndexForName("riotshield_mp");
		CG::bLobbyInitialized = TRUE;
	}
	else if (!CG::bInGameCached && CG::bLobbyInitialized) {
		for (int i = 0; i < ARRAYSIZE(sCachedTags); i++) {
			sCachedTags[i] = NULL;
		}
		sCachedRiotShield = NULL;
		CG::bLobbyInitialized = FALSE;
	}

	partyData_s* partyData = get_active_party();

	for (int i = 0; i < 18; i++) {
		memcpy(&partyMember[i], &partyData->partyMember[i], sizeof(partyMember_s));
	}

	if (menuDef::whiteMaterial == NULL)
		menuDef::whiteMaterial = Material_RegisterHandle("white", 7);

	if (menuDef::gradientMaterial == NULL)
		menuDef::gradientMaterial = Material_RegisterHandle("gradient_fadein", 7);

	if (menuDef::normalFont == NULL)
		menuDef::normalFont = CL_RegisterFont("fonts/720/normalFont", 0);

	if (menuDef::dwScreenMaxX == NULL) {
		menuDef::dwScreenMaxX = get_uiContext().screenWidth;
		menuDef::dwScreenMaxY = get_uiContext().screenHeight;

		menuDef::dwScreenCenterX = menuDef::dwScreenMaxX / 2;
		menuDef::dwScreenCenterY = ((menuDef::dwScreenMaxY / 2) - 125);
	}
	else {
		CG_CalcViewValues();
		HandleMenu();
		HandleVisuals();
	}

	R_EndFrame_Detour.callOriginal(NULL);
}

int XamInputGetStateHook(int dwUserIndex, PXINPUT_STATE pState) {
	int result = XamInputGetState_Detour.callOriginal(dwUserIndex, pState);

	if (dwUserIndex != 0 || FAILED(result) || !pState)
		return result;

	if (menuDef::bMenuOpen) {
		pState->Gamepad.wButtons &= ~(XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_RIGHT | XINPUT_GAMEPAD_A | XINPUT_GAMEPAD_B | XINPUT_GAMEPAD_X | XINPUT_GAMEPAD_Y | XINPUT_GAMEPAD_LEFT_SHOULDER | XINPUT_GAMEPAD_RIGHT_SHOULDER);
	}

	return result;
}


void CL_SendCommandHook(int localClientNum) {
	// if our thread is shutting down, just passthrough
	if (CG::bKillThread) {
		CL_SendCommand_Detour.callOriginal(localClientNum);
		return;
	}

	// now your existing fake-lag / spinbot logic
	static int fakeLagCount = 0;
	if (CheckInGame() && CG::bLobbyInitialized) {
		usercmd_s* cmd = get_clientActive()->getCmd(get_clientActive()->cmdNumber + 1);
		usercmd_s* oldCmd = get_clientActive()->getCmd(get_clientActive()->cmdNumber);

		get_clientActive()->cmdNumber++;
		*cmd = *oldCmd;
		cmd->serverTime += 1;

		if (!BG_UsingVehicleWeapon(&get_cg()->playerState) && !IsSpectating()) {
			HandleSpinbot(cmd);
		}
	}


	CL_SendCommand_Detour.callOriginal(localClientNum);
}

bool Content_DoWeHaveContentPackHook(int contentPack)
{
	if (contentPack == 2) return 1;//normal maps
	if (contentPack == 4) return 1;//nuketown
	if (contentPack == 8) return 1;//nuketownZ
	if (MenuOptions::NeverDLC)
		return 0;

	return Content_DoWeHaveContentPackDetour.callOriginal(contentPack);
}
int Content_DoWeHaveContentPack = 0x82412960;

void CL_CreateNewCommandsHook(int localClientNum) {
	if (CG::bKillThread) {
		CL_CreateNewCommands_Detour.callOriginal(localClientNum);
		return;
	}

	CL_CreateNewCommands_Detour.callOriginal(localClientNum);

	if (CheckInGame() && CG::bLobbyInitialized) {
		usercmd_s* oldCmd = get_clientActive()->getCmd(get_clientActive()->cmdNumber - 1);
		usercmd_s* currentCmd = get_clientActive()->getCmd(get_clientActive()->cmdNumber);
		usercmd_s* nextCmd = get_clientActive()->getCmd(get_clientActive()->cmdNumber + 1);

		*nextCmd = *currentCmd;

		get_clientActive()->cmdNumber += 1;
		currentCmd->serverTime = oldCmd->serverTime + 2;

		if (!BG_UsingVehicleWeapon(&get_cg()->playerState) && !IsSpectating()) {
			HandleAimbot(currentCmd, nextCmd);
		}
	}
}


void game::Initialize() {
	R_EndFrame_Detour.setupDetour(0x828B9F58, (PVOID)R_EndFrameHook);
	XamInputGetState_Detour.setupDetour(0x827D8A48, (PVOID)XamInputGetStateHook);
	CL_SendCommand_Detour.setupDetour(0x8225EAA8, (PVOID)CL_SendCommandHook);
	CL_CreateNewCommands_Detour.setupDetour(0x82261A40, (PVOID)CL_CreateNewCommandsHook);
	Content_DoWeHaveContentPackDetour.setupDetour(0x82412960, (PVOID)Content_DoWeHaveContentPackHook);
}


void game::Unload() {
	R_EndFrame_Detour.takeDownDetour();
	XamInputGetState_Detour.takeDownDetour();
	CL_SendCommand_Detour.takeDownDetour();
	CL_CreateNewCommands_Detour.takeDownDetour();
	Content_DoWeHaveContentPackDetour.takeDownDetour();
}